package com.flowcanto.client;

import java.applet.Applet;
import java.awt.Button;
import java.awt.Label;
import java.awt.Panel;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.stream.StreamResult;

import net.sf.saxon.Controller;
import net.sf.saxon.StandardURIResolver;
import net.sf.saxon.Transform;
import net.sf.saxon.TransformerFactoryImpl;

import org.w3c.dom.Document;
import org.xml.sax.InputSource;

/**
 * Class that makes some tools available to the JScript-code, that can't be done
 * in JScript. Like writing files and doing XSLT2-processing.
 */
public class ToolApplet extends Applet {
	Button openButton;

	/** base directory of application, set to parent of application-directory */
	String baseDir;

	public ToolApplet() {
		Panel p = new Panel();
		this.add( p );

		Transform.now();
	}

	public void start() {
		baseDir = (new File( this.getCodeBase().getPath() )).getPath()
				.replaceAll( "\\\\", "\\/" ) + '/';
		this.add( new Label( '-' + baseDir + '-' ) );
		// System.out.println(loadFile("todo.txt"));
		// saveFile("testhenk.txt", "test write");
		// transformEBSchema("schemas/PurchaseOrder.xsd");
		try {
			Object[] args = { this };
			netscape.javascript.JSObject.getWindow( this ).call(
					"appletLoaded", args );
		} catch( Exception e ) {
		} // to make testing inside appletviewer possible.
	}

	public void doTransform( String stylesheet, String xml, String resultFile ) {
		final String fstylesheet = stylesheet;
		final String fxml = xml;
//		final String fresultFile = resultFile;

		java.security.AccessController
				.doPrivileged( new java.security.PrivilegedAction<String>() {
					public String run() {
						try {
							StandardURIResolver urir = new StandardURIResolver(
									new net.sf.saxon.Configuration() );

							File f = File.createTempFile("ebforms", ".xml");
							FileWriter fw = new FileWriter( f );
							fw.write( fxml );
							fw.flush();
							fw.close();

							Document doc = DocumentBuilderFactory.newInstance()
									.newDocumentBuilder().parse( f );

							System.out.println("compile stylesheet " + baseDir + fstylesheet);
							Source xsl = (Source) urir.resolve( "stylesheets/" 
									+ fstylesheet, baseDir );

							Transformer t = TransformerFactory.newInstance()
									.newTransformer( xsl );

							Source xmlSource = new SAXSource( new InputSource(
									new FileReader( f ) ) );

								File result = File.createTempFile("ebforms", ".bla");
//							File result = new File( 
//								urir.resolve( fresultFile, baseDir ).getSystemId() );
							
							Result res = new StreamResult( result );
							t.transform( xmlSource, res );

						} catch( Exception e ) {
							System.out.println( e.getCause() );
							throw new Error( e );
						}
						return "";
					}
				} );
	}

	
	/**
	 * Takes a schemaName and using the ebform-XSLT-processor to create xhtml
	 * with xforms to create an instance of that schema.
	 * 
	 * @param ebschema
	 *            The Name of the schema to make a message of.
	 * @return The string with the xhtml of the xform.
	 */
	public String transformEBSchema( String ebschema ) {
		final StringWriter res = new StringWriter();
		final String febschema = ebschema;
		java.security.AccessController
				.doPrivileged( new java.security.PrivilegedAction<String>() {
					public String run() {
						try {
							StandardURIResolver urir = new StandardURIResolver(
									new net.sf.saxon.Configuration() );
							TransformerFactoryImpl tfi = new TransformerFactoryImpl();
							Source fxsl = (Source) urir.resolve(
									"stylesheets/Message.xsl", baseDir );
							Controller xsl = (Controller) tfi
									.newTransformer( fxsl );
							xsl.setOutputURIResolver( new ebformsOutputURIResolver(
											baseDir ) );
							Source xsd = (Source) Transform.loadDocuments(
									baseDir + febschema, false, null, false );
							javax.xml.transform.stream.StreamResult resr = new javax.xml.transform.stream.StreamResult(
									res );
							xsl.transform( xsd, resr );

						} catch( TransformerException e ) {
							System.out.println( e.getCause() );
							throw new Error( e );
						}
						return "";
					}
				} );
		// return "";
		return res.toString();
	}

	/**
	 * Loads a file from 
	 the filesystem. Any exceptions are return in the
	 * return-value, since ie can't handle java-exceptions (ff can!).
	 * 
	 * @param fileName
	 *            Name of file, relative to editor-dir.
	 * @return contents of file.
	 * @throws Error
	 *             when trying to get a file outside editor-space.
	 */
	public String loadFile( String fileName ) {
		final StringWriter res = new StringWriter();
		if( fileName.indexOf( ".." ) != -1 )
			throw new Error( "tried to load illegal file!" ); // keep within
																// base-dir.
		final String filePath = baseDir + fileName;
		// read the annotation file
		java.security.AccessController
				.doPrivileged( new java.security.PrivilegedAction<Object>() {
					public Object run() {
						// File wfile = new
						// File("Annotations"+wfile.separatorChar+fileName+".xml");
						try {
							BufferedReader lfile = new BufferedReader(
									new FileReader( filePath ) );
							String line;
							while( (line = lfile.readLine()) != null ) {
								res.write( line + "\n" );
							}
							lfile.close();
						} catch( SecurityException se ) {
							System.out.println( "Caught a security exception" );
							se.printStackTrace();
							return "Exception:SecurityException";
						} catch( FileNotFoundException fnf ) {
							System.out.println( "File not found..." );
							return "Exception:FileNotFoundException";
						} catch( IOException iox ) {
							System.out.println( "File read error..." );
							iox.printStackTrace();
							return "Exception:IOException";
						}
						return null;
					}
				} );
		return res.toString();
	}

	public String tmpFile() {
		String fileName;	
		try {
			fileName = File.createTempFile("ebforms", "").getAbsolutePath();
		} catch (Exception e) {
			throw new Error("could not create temp file", e);	
		}
		return fileName;				
	}
	
	public String saveFileTMP (String contents, String prefix, String suffix) {
		String fileName;	
		try {
			fileName = File.createTempFile(prefix, suffix).getAbsolutePath();
		} catch (Exception e) {
			throw new Error("could not create temp file", e);	
		}
		saveFile(fileName, contents);
		return fileName;	
	}
		
	public boolean saveFile( String fileName, String contents ) {
		if( fileName.indexOf( ".." ) != -1 )
			throw new Error( "tried to load illegal file!" ); // keep within base-dir.
		final String filePath = baseDir + fileName;
		System.err.println("writing file: " + filePath);
		final String fcontents = contents;
		// save the annotation file
		Boolean res = java.security.AccessController
		 .doPrivileged( new java.security.PrivilegedAction<Boolean>() {
			public Boolean run() {
	 			try {
					PrintWriter sfile = new PrintWriter( new FileWriter( filePath ), true );
					sfile.print( fcontents );
					sfile.close();
					return new Boolean(true);
				} catch( SecurityException se ) {
					System.out.println( "Caught a security exception" );
					se.printStackTrace();
				} catch( IOException iox ) {
					System.out.println( "File save error..." );
					iox.printStackTrace();
				}
				return new Boolean(false);
			}
		} );
		return res.booleanValue();
	}
	
	private class ebformsOutputURIResolver implements
			net.sf.saxon.OutputURIResolver {
		String appBase;

		public ebformsOutputURIResolver( String applicationBaseDirectory ) {
			appBase = applicationBaseDirectory;
		}

		public void close( javax.xml.transform.Result result ) {
		}

		/**
		 * @param href
		 *            The relative URI of the output document. This corresponds
		 *            to the href attribute of the xsl:result-document
		 *            instruction.
		 * @param base
		 *            The base URI that should be used. This is the base URI of
		 *            the element that contained the href attribute. It may be
		 *            null if no systemID was supplied for the stylesheet.
		 */
		public javax.xml.transform.Result resolve( java.lang.String href,
				java.lang.String base ) {
			String abhref;
			if( href.startsWith( "." ) )
				abhref = appBase + href;
			else
				abhref = href;

			return new javax.xml.transform.stream.StreamResult( new File(
					abhref ) );
		}
	}

}